﻿namespace MefContrib.Models.Provider.Definitions.Configurable
{
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Diagnostics;
    using System.Linq;
    using MefContrib.Models.Provider;
    using MefContrib.Models.Provider.Validation;

    /// <summary>
    /// 
    /// </summary>
    public class ConfigurableDefinitionProvider : DefinitionProvider
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ConfigurableDefinitionProvider"/> class, using
        /// the specified configuration section name.
        /// </summary>
        /// <param name="configurationSectionName">The name of the configuration section which contains the definitions.</param>
        /// <exception cref="ArgumentNullException">The value of the <paramref name="configurationSectionName"/> parameter cannot be null or empty.</exception>
        public ConfigurableDefinitionProvider(string configurationSectionName)
        {
            configurationSectionName
                .Require("configurationSectionName")
                .NotNull();

            this.ConfigurationSection =
                ConfigurationManager.GetSection(configurationSectionName) as PartCatalogConfigurationSection;
        }

        /// <summary>
        /// Gets the name of the configuration section which is being used by the <see cref="ConfigurableDefinitionProvider"/>.
        /// </summary>
        /// <value>A <see cref="String"/> containing the name of the configuration section.</value>
        public string ConfigurationSectionName
        {
            [DebuggerStepThrough]
            get { return this.ConfigurationSection.SectionInformation.Name; }
        }

        /// <summary>
        /// Gets a list of all discovered parts.
        /// </summary>
        /// <value>An <see cref="IQueryable{T}"/> object.</value>
        public override IEnumerable<PartDescription> Parts
        {
            [DebuggerStepThrough]
            get
            {
                List<PartDescription> declarations =
                    new List<PartDescription>();

                foreach (PartCatalogConfigurationPart part in this.ConfigurationSection.Parts)
                {
                    declarations.Add(
                        new PartDescription(
                            part.Type,
                            part.Exports.AsCollection(),
                            part.Imports.AsCollection()));
                }

                return declarations.AsQueryable();
            }
        }

        /// <summary>
        /// Gets or sets the reference to the configuration section.
        /// </summary>
        /// <value>A <see cref="PartCatalogConfigurationSection"/> object.</value>
        private PartCatalogConfigurationSection ConfigurationSection { get; set; }
    }
}